#include "gdal/include/gdal_priv.h"
#include "gdal/include/ogrsf_frmts.h"
#pragma comment(lib,"gdal/gdal_i.lib")
#include "RasterIO.h"
#include "pch.h"
#include "VectorIO.h"

BOOL VectorIO::OpenVector(CString FileName)
{
	pVDatasetR = NULL;//设置矢量图形的句柄

	//pDataset = (GDALDataset *)GDALOpen("H:\\GDAL\\Polygon.shp", GA_ReadOnly);
	pVDatasetR = (GDALDataset *)GDALOpenEx(FileName, GDAL_OF_VECTOR, NULL, NULL, NULL);
	//使用函数打开矢量图形

	if (pVDatasetR == NULL)
	{
		AfxMessageBox("打开文件失败");
		return FALSE;
	}//判断是否打开成功
	return TRUE;
}

BOOL VectorIO::CreateVector(CString FileName)
{
	pVDriverW = NULL;//设置相应文件格式的驱动
	pVDriverW = GetGDALDriverManager()->GetDriverByName("ESRI Shapefile");//设置文件格式

	pVDatasetW = NULL;//设置写入文件的句柄
	pVDatasetW = pVDriverW->Create(FileName, 0, 0, 0, GDT_Unknown, NULL);//设置写入参数
	//建立该文件

	if (pVDatasetW == NULL)
	{
		return FALSE;
	}

	return TRUE;
}

BOOL VectorIO::CloseVector(GDALDataset * Dataset)
{
	GDALClose(Dataset);//关闭pDataset文件

	return TRUE;
}

BOOL VectorIO::ReadVectorInfo(int iBand)
{
	iLayerNum = pVDatasetR->GetLayerCount();//得到图层信息
	OGRLayer * pLayer = pVDatasetR->GetLayer(iBand);//用指针返回对应图层的信息，此处参数为0
	//如果没有对应的图层，就会返回NULL
	//矢量图层的图层是从0开始编号，而栅格图像的图层是从1开始编号的

	pVDatasetR->GetLayer(iBand)->GetExtent(&Envelope);//获取空间范围
	strLayerName = pLayer->GetName();//返回涂层的名字
	SpatialReference = pLayer->GetSpatialRef();//返回图层的空间参考
	//空间参考包括投影的参数
	//OGRSpatialReference的使用十分麻烦，所以尽量不要修改，此处只是利用这个格式进行保存

	GeometryType = pLayer->GetGeomType();//得到图层中几何图元的类型
	//在一个shp文件中，有且只能由同一种的几何图元的类型
	//几何图元的类型包括点、线、面

	iFeatureNum = pLayer->GetFeatureCount();//获取图层中总共的对象数量
	//图层中对象数量可能会非常多，所以要使用八个字节来保存

	return TRUE;
}

BOOL VectorIO::ReadVectorDefn(int iBand, int iFeature)
{
	OGRLayer * pLayer = pVDatasetR->GetLayer(iBand);//用指针返回对应图层的信息，此处参数为0
	//如果没有对应的图层，就会返回NULL
	//矢量图层的图层是从0开始编号，而栅格图像的图层是从1开始编号的

	OGRFeature * pFeature = pLayer->GetFeature(iFeature);//读取对象，返回一个OGRFeature的指针

	pAttribute = pLayer->GetLayerDefn();//获取属性表结构
	iFieldNum = pAttribute->GetFieldCount();//获取字段数量

	OGRFieldDefn * pField = NULL;//定义一个空的字段指针

	FieldTypes.clear();//定义一个类型容器并清空

	FieldNames.clear();//定义一个数值容器并清空

	for (int i = 0; i < iFieldNum; i++)//扫描字段，直到所有字段全部都被扫描
	{
		pField = pAttribute->GetFieldDefn(i);//扫描第i个字段
		OGRFieldType type = pField->GetType();//获取该字段的类型
		CString strName = pField->GetNameRef();//获取该字段名的名字

		FieldTypes.push_back(type);//将类型装入容器
		FieldNames.push_back(strName);//将名字装入容器
	}

	FieldsValue.clear();//定义一个字段数值容器并清空

	for (int i = 0; i < iFieldNum; i++)//扫描字段，直到所有字段全部都被扫描
	{
		CString strValue = pFeature->GetFieldAsString(i);//把字段提取出来，并以字符串形式提取
		//不管原来字符是什么类型，最后返回的都是字符串类型
		FieldsValue.push_back(strValue);//将数值装入容器
	}
	return TRUE;
}

BOOL VectorIO::ReadVectorExRing(int iBand, int iFeature)
{
	OGRLayer * pLayer = pVDatasetR->GetLayer(iBand);//用指针返回对应图层的信息，此处参数为0
	//如果没有对应的图层，就会返回NULL
	//矢量图层的图层是从0开始编号，而栅格图像的图层是从1开始编号的

	OGRFeature * pFeature = pLayer->GetFeature(iFeature);//读取对象，返回一个OGRFeature的指针

	pGeometry = pFeature->GetGeometryRef();//读取空间信息，保存到pGeometry中
	type = wkbFlatten(pGeometry->getGeometryType());//用于获取几何图元的类型
	pOGRPolygon = (OGRPolygon *)pGeometry;//把通用的数据类型强制转化为面信息的强制转化
	//一般操作顺序为获取数据类型之后根据类型进行转化，这边直接用面信息进行转化

	OGRLinearRing * pRing = pOGRPolygon->getExteriorRing();//获取外环指针
	//获取外环指针不需要参数，因为外环有且只有一个
	MyPolygon.ExRing.iPtNum = pRing->getNumPoints();//获取外环的节点数量
	for (int i = 0; i < MyPolygon.ExRing.iPtNum; i++)//扫描所有的节点
	{
		MY_PT MyPt;
		MyPt.dX = pRing->getX(i);//获取第i个节点的横坐标
		MyPt.dY = pRing->getY(i);//获取第i个节点的纵坐标
		MyPolygon.ExRing.PtList.push_back(MyPt);//将这个节点存入MyPolygon的外环中
	}
	return TRUE;
}

BOOL VectorIO::ReadVectorInRing(int iBand, int iFeature)
{
	OGRLayer * pLayer = pVDatasetR->GetLayer(iBand);//用指针返回对应图层的信息，此处参数为0
	//如果没有对应的图层，就会返回NULL
	//矢量图层的图层是从0开始编号，而栅格图像的图层是从1开始编号的

	OGRFeature * pFeature = pLayer->GetFeature(iFeature);//读取对象，返回一个OGRFeature的指针

	pGeometry = pFeature->GetGeometryRef();//读取空间信息，保存到pGeometry中
	type = wkbFlatten(pGeometry->getGeometryType());//用于获取几何图元的类型
	pOGRPolygon = (OGRPolygon *)pGeometry;//把通用的数据类型强制转化为面信息的强制转化
	//一般操作顺序为获取数据类型之后根据类型进行转化，这边直接用面信息进行转化

	MyPolygon.iInRingNum = pOGRPolygon->getNumInteriorRings();//获取内环的数量
	for (int k = 0; k < MyPolygon.iInRingNum; k++)//扫描所有的内环
	{
		OGRLinearRing * pHole = pOGRPolygon->getInteriorRing(k);//获取内环的指针，参数为第i个内环

		MY_RING MyHoleTmp;//构建内环
		MyHoleTmp.iPtNum = pHole->getNumPoints();//获取内环的节点数量
		for (int i = 0; i < MyHoleTmp.iPtNum; i++)//扫描内环中所有的节点
		{
			MY_PT MyPt;
			MyPt.dX = pHole->getX(i);//获取第i个节点的横坐标
			MyPt.dY = pHole->getY(i);//获取第i个节点的纵坐标

			MyHoleTmp.PtList.push_back(MyPt);//将这个节点存入MyHoleTmp中
		}

		MyPolygon.InRings.push_back(MyHoleTmp);//将MyHoleTmp存入MyPolygon中
	}

	return TRUE;
}

BOOL VectorIO::WriteVector(int iBand, int iFieldNumW, vector<CString>FieldNameW, vector<double> FieldValueW, int ploynum)
{
	OGRLayer * pVLayerW = NULL;//新建图层句柄

	pVLayerW = pVDatasetW->CreateLayer(strLayerName, SpatialReference, GeometryType, NULL);//写入图层
	//图层名字，空间参考，图元类型

	CString Name[6];
	double Value[6];

	for (int i = 0; i < iFieldNumW; i++)
	{
		
		CString Name1 = *(FieldNameW.end() - 1 - i);
		double Value1 = *(FieldValueW.end() - 1 - i);

		Name[i] = Name1;
		Value[i] = Value1;

	}

	FieldTypesW.clear();
	FieldNamesW.clear();
	FieldsValueW.clear();

	for (int i = 0; i < iFieldNumW; i++)//扫描所有字段
	{
		FieldNamesW.push_back(Name[iFieldNumW - i - 1]);
		FieldTypesW.push_back(OFTReal);
	}

	for (int i = 0; i < iFieldNumW; i++)//扫描所有字段
	{
		OGRFieldDefn FieldTmp(FieldNamesW[i], FieldTypesW[i]);//定义字段（字段名，字段类型）
		pVLayerW->CreateField(&FieldTmp);//创建属性表
	}

	pVLayerW = pVDatasetW->GetLayer(iBand);//获取图层

	OGRFeature * pFeatureW = NULL;//建立属性表对象
	pFeatureW = OGRFeature::CreateFeature(pVLayerW->GetLayerDefn());//根据当前属性表结构创建一个新的对象

	for (int i = 0; i < iFieldNumW; i++)//扫描所有字段
	{
		pFeatureW->SetField(FieldNamesW[i], Value[iFieldNumW - i - 1]);//将属性表中的值进行赋值
	}
	//SetField为写属性信息的函数

	OGRPolygon PolygonTmp;
	OGRLinearRing RingTmp;

	for (int i = 0; i < MyPolygon.ExRing.iPtNum; i++)//扫描外环所有节点
	{
		RingTmp.addPoint(MyPolygon.ExRing.PtList[i].dX, MyPolygon.ExRing.PtList[i].dY);//逐个添加节点
	}
	RingTmp.closeRings();//封闭环

	PolygonTmp.addRing(&RingTmp);//添加环
	//第一个添加的环自动默认为外环，后面添加的环为内环

	for (int k = 0; k < MyPolygon.iInRingNum; k++)//扫描所有内环
	{
		RingTmp.empty();//清空内环，可以重复利用

		for (int i = 0; i < MyPolygon.InRings[k].iPtNum; i++)//扫描第k个内环的所有节点
		{
			RingTmp.addPoint(MyPolygon.InRings[k].PtList[i].dX, MyPolygon.InRings[k].PtList[i].dY);//逐个添加节点
		}
		RingTmp.closeRings();//封闭环
		PolygonTmp.addRing(&RingTmp);//添加环
	}

	pFeatureW->SetGeometry(&PolygonTmp);
	//SetGeometry为写空间信息的函数

	pVLayerW->CreateFeature(pFeatureW);//写入Layer

	return TRUE;
}
